#include "cmd.h"

#include "../com/mem.h"


#define CMDTYPE_FUNC	1
#define CMDTYPE_ALIAS	2

#define MAX_LINE_LEN    1024

struct TCmdStruct
{
	int type;
	char *name;
	union
	{
		TCmdFunc asFunc;
		char *asAlias;
	};
	TCmdStruct *next;
};

static TCmdStruct *commands;


////////////////////////////////////////////////////////////////////////////////
// cmdList functions
////////////////////////////////////////////////////////////////////////////////

static TCmdStruct *findPrevCmd(char *name)
{
	TCmdStruct *ptr = commands;

	while (ptr->next)
	{
		if (!strcmp(name, ptr->next->name))
			return ptr;

		ptr = ptr->next;
	}

	return NULL;
}

////////////////////////////////////////////////////////////////////////////////
// main functions
////////////////////////////////////////////////////////////////////////////////

bool cmd_init()
{
	commands = NEW TCmdStruct;
	commands->type = 0;
	commands->name = NULL;
	commands->next = NULL;

	return true;
}

bool cmd_shutdown()
{
	TCmdStruct *ptr = commands->next;

	while(ptr)
	{
		commands->next = ptr->next;
		SAFE_DEL_ARRAY(ptr->name);
		if (ptr->type == CMDTYPE_ALIAS)
			SAFE_DEL_ARRAY(ptr->asAlias);
	}

	SAFE_DEL(commands);

	return true;
}

bool cmd_add(char *name, char *alias)
{
	if (findPrevCmd(name))
		return false;

	TCmdStruct *ptr = NEW TCmdStruct;
	ptr->type = CMDTYPE_ALIAS;
	STRDUP(ptr->name, name);
	STRDUP(ptr->asAlias, alias);
	ptr->next = commands->next;
	commands->next = ptr;

	return true;
}

bool cmd_add(char *name, TCmdFunc func)
{
	if (findPrevCmd(name))
		return false;

	TCmdStruct *ptr = NEW TCmdStruct;
	ptr->type = CMDTYPE_FUNC;
	STRDUP(ptr->name, name);
	ptr->asFunc = func;
	ptr->next = commands->next;
	commands->next = ptr;

	return true;
}

bool cmd_remove(char *name)
{
	TCmdStruct *ptr = findPrevCmd(name);

	if (!ptr)
		return false;

	TCmdStruct *ptr2 = ptr->next;

	ptr->next = ptr->next->next;

	SAFE_DEL_ARRAY(ptr2->name);
	if (ptr2->type == CMDTYPE_ALIAS)
		SAFE_DEL_ARRAY(ptr2->asAlias);

	SAFE_DEL(ptr2);

	return true;
}

bool cmd_exec(char *str, TCmdParam &result)
{

	return false;
}

bool cmd_execFile(char *fname, TCmdParam &result)
{
	return false;
}

char *cmd_nextToken(char *str, TCmdParam &token)
{
    token.type = CMDPARAM_NULL;
    token.asBool = 0;
    token.asNumber = 0;
    token.asText = NULL;

    //jump whitespace
    while (*str && (*str == ' '))
        str ++;

    char s[MAX_LINE_LEN];
    int p = 0;

    if (*str == '"')
    {
        //read string
    }
    else
    {
        while (*str && (
            ((*str >= 'a') && (*str <= 'z')) ||
            ((*str >= 'A') && (*str <= 'Z')) ||
            ((*str >= '0') && (*str <= '9')) ||
            (*str == '_') ||
            (*str == '-') ||
            (*str == '.')))
        {
            s[p] = *str;
            p++;
            str++;
        }
        s[p] = 0;
    }

    bool gotDot = false;
    bool isNumber = true;
    p = 0;

    while (s[p] && isNumber)
    {
        if (s[p] == '.')
        {
            if (gotDot)
                isNumber = false;
            else
                gotDot = true;
        }
        else
        {
            if (((s[p] < '0') || (s[p] > '9'))&&(s[p] != '-'))
                isNumber = false;
        }
    }

    if (isNumber)
    {
        token.type |= CMDPARAM_NUMBER;
        if (gotDot)
            token.asNumber = (float)atof(s);
        else
            token.asNumber = atoi(s);
    }
    else
    {
        token.type |= CMDPARAM_TEXT;
        STRDUP(token.asText, s);
    }

    if (token.type & CMDPARAM_TEXT)
    {
        if (stricmp(token.asText, "TRUE"))
        {
            token.type |= CMDPARAM_BOOL;
            token.asBool = 1;
        }
        else if (stricmp(token.asText, "FALSE"))
        {
            token.type |= CMDPARAM_BOOL;
            token.asBool = 0;
        }
    }

    if (token.type & CMDPARAM_NUMBER)
    {
        token.type |= CMDPARAM_BOOL;
        if (token.asNumber != 0)
            token.asBool = 1;
        else
            token.asBool = 0;
    }

    return str;
}
